<?php

namespace app\admin\controller;

use think\Controller;
use think\Db;
use think\Request;

/**
 * 基础控制器
 * 提供通用的CRUD操作和自动时间填充、软删除功能
 */

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");                // 允许的方法
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");  // 允许的请求头
//header("Access-Control-Allow-Credentials: true"); // 允许携带cookie
header("Access-Control-Expose-Headers: Authorization"); // 允许客户端获取的响应头

class BaseController extends Controller
{
    // 模型实例
    protected $model;

    // 模型名称，由子类设置
    protected $modelName = '';

    // 验证规则，由子类设置
    protected $validateRules = [];

    // 验证规则，由子类设置
    protected $validateRulesMsg = [];

    // 唯一性字段，由子类设置
    protected $uniqueFields = [];

    // 需要结合父ID进行唯一性检查的字段，由子类设置
    protected $uniqueWithParentFields = [];

    // 父ID字段名，默认'pid'
    protected $parentIdField = 'pid';

    // 字段显示名称映射，由子类设置
    // 格式: ['field_name' => '显示名称']
    protected $fieldLabels = [];

    // 是否使用软删除，由子类设置
    protected $useSoftDelete = false;

    /**
     * 获取字段的显示名称
     * @param string $field 字段名
     * @return string 显示名称
     */
    protected function getFieldLabel($field)
    {
        return $this->fieldLabels[$field] ?: $field;
    }

    /**
     * 检查字段唯一性
     * @param array $data 要检查的数据
     * @param int $id 排除的ID（编辑时使用）
     * @return bool|string 成功返回true，失败返回错误信息
     */
    protected function checkUnique($data, $id = 0)
    {
        // 检查普通唯一性字段
        if (!empty($this->uniqueFields)) {
            foreach ($this->uniqueFields as $field) {
                if (!isset($data[$field])) {
                    continue;
                }

                $query = $this->model->where($field, $data[$field]);

                // 如果是编辑，排除当前记录
                if ($id > 0) {
                    $query->where('id', '<>', $id);
                }

                // 如果表中有delete_time字段，只检查未删除的记录
                if ($this->hasField('delete_time')) {
                    $query->where('delete_time', 0);
                }

                if ($query->count() > 0) {
                    $label = $this->getFieldLabel($field);
                    return "{$label}已存在";
                }
            }
        }

        // 检查需要结合父ID的唯一性字段
        if (!empty($this->uniqueWithParentFields)) {
            $parentId = $data[$this->parentIdField] ?: 0;

            foreach ($this->uniqueWithParentFields as $field) {
                if (!isset($data[$field])) {
                    continue;
                }

                $query = $this->model->where($field, $data[$field])
                    ->where($this->parentIdField, $parentId);

                // 如果是编辑，排除当前记录
                if ($id > 0) {
                    $query->where('id', '<>', $id);
                }

                // 如果表中有delete_time字段，只检查未删除的记录
                if ($this->hasField('delete_time')) {
                    $query->where('delete_time', 0);
                }

                if ($query->count() > 0) {
                    $label = $this->getFieldLabel($field);
                    return "在当前分类层级下，{$label}已存在";
                }
            }
        }

        return true;
    }

    /**
     * 构造函数
     */
    public function __construct()
    {
        parent::__construct();

        // 处理CORS预检请求
        $this->handleCors();

        // 初始化模型
        if (!empty($this->modelName)) {
            $this->model = Db::name($this->modelName);
        }
    }

    /**
     * 处理CORS请求
     */
    protected function handleCors()
    {
        // 处理OPTIONS请求
        if ($this->request->method() === 'OPTIONS') {
            apiReturn(1, 'OPTIONS请求成功');
        }
    }

    /**
     * 检查表中是否存在指定字段
     * @param string $field 字段名
     * @return bool
     */
    protected function hasField($field)
    {
        // 静态缓存，避免同一请求中重复查询
        static $fieldsCache = [];

        $tableName = $this->model->getTable();
        $cacheKey = $tableName . '_fields';

        // 如果缓存中没有该表的字段信息，则查询并缓存
        if (!isset($fieldsCache[$cacheKey])) {
            try {
                $fields = $this->model->getTableFields();
                $fieldsCache[$cacheKey] = $fields;
            } catch (\Exception $e) {
                $fieldsCache[$cacheKey] = [];
            }
        }

        return in_array($field, $fieldsCache[$cacheKey]);
    }

    /**
     * 获取列表（带可选分页）
     */
    public function getList()
    {
        if (empty($this->modelName)) {
            apiReturn(2, '模型名称未设置');
        }

        // 获取分页参数
        $page = $this->request->param('page');
        $pageSize = $this->request->param('pageSize');
        $order = $this->request->param('order', 'id desc');

        // 检查表中是否有delete_time字段
        if ($this->hasField('delete_time')) {
            $query = $this->model->where('delete_time', 0);
        } else {
            $query = $this->model;
        }

        // 判断是否需要分页
        if (isset($page) && isset($pageSize)) {
            // 确保参数为整数
            $page = intval($page);
            $pageSize = intval($pageSize);
            
            // 计算总数
            $total = $query->count();
            // 计算总页数
            $currentPage = ceil($total / $pageSize);
            // 获取列表数据
            $list = $query->order($order)->page($page, $pageSize)->select();

            // 构建分页信息
            $pagination = [
                'page' => $page,
                'pageSize' => $pageSize,
                'total' => $total,
                'currentPage' => $currentPage
            ];

            // 构建返回数据
            $result = [
                'list' => $list,
                'pagination' => $pagination
            ];
        } else {
            // 不需要分页，返回全部数据
            $list = $query->order($order)->select();
            $result = [
                'list' => $list
            ];
        }

        apiReturn(1, '获取数据成功', $result);
    }

    /**
     * 新增/编辑前的钩子方法
     * 子类可以重写此方法来处理数据
     * @param array $data 要处理的数据
     * @return array 处理后的数据
     */
    protected function beforeAddOrEdit($data)
    {
        return $data;
    }

    /**
     * 新增/编辑
     */
    public function addOrEdit()
    {
        if (empty($this->modelName)) {
            apiReturn(2, '模型名称未设置');
        }

        $input = $this->request->param();
        $id = $input['id'] ?: 0;

        // 如果设置了验证规则，则进行验证
        if (!empty($this->validateRules)) {
            $validate = new \think\Validate($this->validateRules, $this->validateRulesMsg);
            if (!$validate->check($input)) {
                apiReturn(2, $validate->getError());
            }
        }

        // 检查唯一性
        $uniqueResult = $this->checkUnique($input, $id);
        if ($uniqueResult !== true) {
            apiReturn(2, $uniqueResult);
        }

        // 过滤不需要的字段
        $data = [];
        foreach ($input as $key => $value) {
            if (in_array($key, array_keys($this->validateRules)) || $key == 'id') {
                $data[$key] = $value;
            }
        }

        // 调用新增/编辑前的钩子方法
        $data = $this->beforeAddOrEdit($data, $id);

        try {
            if ($id > 0) {
                $data['update_time'] = time();
                $res = $this->model->where(['id' => $id])->update($data);
                if ($res !== false) {
                    apiReturn(1, '编辑成功');
                } else {
                    apiReturn(2, '编辑失败');
                }
            } else {
                $data['create_time'] = time();
                // 如果表中有delete_time字段，初始化它
                if ($this->hasField('delete_time')) {
                    $data['delete_time'] = 0;
                }
                $res = $this->model->insert($data);
                if ($res) {
                    apiReturn(1, '新增成功');
                } else {
                    apiReturn(2, '新增失败');
                }
            }
        } catch (\Exception $e) {
            apiReturn(2, '操作失败11' . $e->getMessage());
        }
    }

    /**
     * 删除记录（支持级联删除）
     * 根据$useSoftDelete属性决定是物理删除还是软删除
     * 如果被删除的数据有子元素，子元素也会被级联删除
     */
    public function delete()
    {
        if (empty($this->modelName)) {
            apiReturn(2, '模型名称未设置');
        }

        $input = $this->request->param();
        $id = $input['id'] ?: 0;

        if (empty($id)) {
            apiReturn(2, '参数错误');
        }

        try {
            // 开启事务
            Db::startTrans();
            
            // 获取所有需要删除的ID（包括子元素）
            $allIds = $this->getAllChildIds([$id]);
            
            if ($this->useSoftDelete) {
                // 软删除: 检查表中是否有delete_time字段
                if (!$this->hasField('delete_time')) {
                    Db::rollback();
                    apiReturn(2, '该表不支持软删除功能，表中缺少delete_time字段');
                }

                $data = [
                    'delete_time' => time(),
                    'update_time' => time()
                ];
                $res = $this->model->where('id', 'in', $allIds)->update($data);
                $success = $res !== false;
            } else {
                // 物理删除
                $success = $this->model->where('id', 'in', $allIds)->delete();
            }

            Db::commit();
            
            if ($success) {
                apiReturn(1, '删除成功', ['deleted_count' => count($allIds)]);
            } else {
                apiReturn(2, '删除失败');
            }
        } catch (\Exception $e) {
            Db::rollback();
            apiReturn(2, '操作失败: ' . $e->getMessage());
        }
    }

    /**
     * 递归获取所有子元素ID
     * @param array $parentIds 父元素ID数组
     * @return array 包含所有子元素ID的数组
     */
    protected function getAllChildIds(array $parentIds)
    {
        // 已获取的所有ID
        $allIds = $parentIds;
        
        // 用来存储当前层级的子ID
        $childIds = [];
        
        // 构建查询条件
        $query = $this->model;
        // 如果表中有delete_time字段，只查询未删除的记录
        if ($this->hasField('delete_time')) {
            $query->where('delete_time', 0);
        }
        
        // 获取当前父ID的直接子ID
        $childIds = $query->where($this->parentIdField, 'in', $parentIds)->column('id');
        
        // 如果有子ID，递归获取所有层级的子ID
        if (!empty($childIds)) {
            $allIds = array_merge($allIds, $this->getAllChildIds($childIds));
        }
        
        return $allIds;
    }

    /**
     * 一键删除（批量删除，支持级联删除）
     * 支持删除多个记录，根据$useSoftDelete属性决定是物理删除还是软删除
     * 如果被删除的数据有子元素，子元素也会被级联删除
     */
    public function batchDelete()
    {
        if (empty($this->modelName)) {
            apiReturn(2, '模型名称未设置');
        }

        $input = $this->request->param();
        $ids = $input['ids'] ?: [];

        // 参数验证
        if (empty($ids) || !is_array($ids)) {
            apiReturn(2, '参数错误，ids必须是非空数组');
        }

        // 过滤非数字ID
        $validIds = array_filter($ids, function($id) {
            return is_numeric($id) && $id > 0;
        });

        if (empty($validIds)) {
            apiReturn(2, '参数错误，请提供有效的ID');
        }

        try {
            Db::startTrans();
            
            // 获取所有需要删除的ID（包括子元素）
            $allIds = $this->getAllChildIds($validIds);
            $deletedCount = 0;
            
            if ($this->useSoftDelete) {
                // 软删除: 检查表中是否有delete_time字段
                if (!$this->hasField('delete_time')) {
                    Db::rollback();
                    apiReturn(2, '该表不支持软删除功能，表中缺少delete_time字段');
                }

                $data = [
                    'delete_time' => time(),
                    'update_time' => time()
                ];
                $deletedCount = $this->model->where('id', 'in', $allIds)->update($data);
            } else {
                // 物理删除
                $deletedCount = $this->model->where('id', 'in', $allIds)->delete();
            }

            Db::commit();
            
            if ($deletedCount > 0) {
                apiReturn(1, "成功删除 {$deletedCount} 条记录", [
                    'deleted_count' => $deletedCount,
                    'original_ids_count' => count($validIds),
                    'cascade_ids_count' => count($allIds) - count($validIds)
                ]);
            } else {
                apiReturn(2, '没有记录被删除，请检查ID是否存在');
            }
        } catch (\Exception $e) {
            Db::rollback();
            apiReturn(2, '批量删除失败: ' . $e->getMessage());
        }
    }

    /**
     * 恢复软删除的记录
     */
    public function restore()
    {
        if (empty($this->modelName)) {
            apiReturn(2, '模型名称未设置');
        }

        // 检查表中是否有delete_time字段
        if (!$this->hasField('delete_time')) {
            apiReturn(2, '该表不支持软删除功能，表中缺少delete_time字段');
        }

        $input = $this->request->param();
        $id = $input['id'] ?: 0;

        if (empty($id)) {
            apiReturn(2, '参数错误');
        }

        try {
            $data = [
                'delete_time' => 0,
                'update_time' => time()
            ];
            $res = $this->model->where('id', $id)->update($data);
            if ($res !== false) {
                apiReturn(1, '恢复成功');
            } else {
                apiReturn(2, '恢复失败');
            }
        } catch (\Exception $e) {
            apiReturn(2, '操作失败: ' . $e->getMessage());
        }
    }

    /**
     * 排序
     */
    public function sort()
    {
        if (empty($this->modelName)) {
            apiReturn(2, '模型名称未设置');
        }

        $input = $this->request->param();

        if (empty($input['list']) || !is_array($input['list'])) {
            apiReturn(2, '参数错误');
        }

        // 验证所有项是否都包含id和sort
        foreach ($input['list'] as $item) {
            if (!isset($item['id']) || !isset($item['sort'])) {
                apiReturn(2, '参数格式错误，每项必须包含id和sort');
            }
        }

        try {
            Db::startTrans();

            foreach ($input['list'] as $item) {
                $this->model->where('id', $item['id'])->update([
                    'sort' => $item['sort'],
                    'update_time' => time()
                ]);
            }

            Db::commit();
            apiReturn(1, '更新排序成功');
        } catch (\Exception $e) {
            Db::rollback();
            apiReturn(2, '更新排序失败');
        }
    }

    /**
     * 禁用/启用
     */
    public function doStatus()
    {
        if (empty($this->modelName)) {
            apiReturn(2, '模型名称未设置');
        }

        $input = $this->request->param();
        $id = $input['id'];
        $status = $input['status'];

        if (empty($id)) {
            apiReturn(2, '参数错误');
        }

        try {
            $data = [
                'status' => $status,
                'update_time' => time()
            ];
            $res = $this->model->where('id', $id)->update($data);
            if ($res !== false) {
                apiReturn(1, '操作成功');
            } else {
                apiReturn(2, '操作失败');
            }
        } catch (\Exception $e) {
            apiReturn(2, '操作失败: ' . $e->getMessage());
        }
    }
}
